using Irc;
using System;
using Irc.Events;
using Irc.Objects;
using System.Data;
using System.Text;
using System.Drawing;
using System.Net.Security;
using System.Windows.Forms;
using System.ComponentModel;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System.Security.Authentication;
using System.Security.Cryptography.X509Certificates;

namespace Irc.Net
{
	public partial class Network : Form
	{
		public bool IsConnected
		{
			get { return client.Registered; }
		}
		public Client Client
		{
			get { return this.client; }
		}
//		private Dictionary<string,Delegate> cmds = new Dictionary<string,Delegate>();
		private Client client;
		private Regex ircstring = new Regex(@"^irc(?<ssl>s)?:\/\/(?<server>.+?):?(?<port>[0-9]{1,6})?(\/(?<other>.+))?$",
											RegexOptions.Compiled | RegexOptions.ExplicitCapture | RegexOptions.IgnoreCase);
		public Network(Main owner, string conString, string nick, string real, string user, string pass)
		{
			string server;
			int port;
			bool ssl;
			Match options = ircstring.Match(conString);
			if(options.Success)
			{
				server = options.Groups["server"].Value;
				port = options.Groups["port"].Success ? Convert.ToInt32(options.Groups["port"].Value) : 6667;
				ssl = options.Groups["ssl"].Success ? true : false;
				client = new Client(new Servername(server, port, ssl), new Nickname(nick, real, "*", user), pass);
				client.SslCertValidation += ValidateCert;
				client.Debug = SettingsManager.Instance.DebugMessages;
				InitializeComponent();
				MdiParent = (Form)owner;
				Text = Name = server;
				serverTab.Text = client.Server;
				ServerTab serverWindow = new ServerTab(client.Server);
				serverTab.Controls.Add(serverWindow);
				serverTab.GotFocus += delegate { serverWindow.Refocus(); };
				tabs.TabClosing += delegate(object sender, CancelEventArgs e) {
					if(tabs.ClosingTab == serverTab)
						e.Cancel = true;
					else if(SettingsManager.Instance.ConfirmClose && DialogResult.No == MessageBox.Show("Are you sure you want to close \""+tabs.ClosingTab.Text+"\"?", "Confirm", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2))
						e.Cancel = true;
				};
				#region debug message event handler
				client.DebugMessage += delegate(object sender, MessageEventArgs e)
				{
					ServerWindow.AddMessage(e.Message);
				};
				#endregion
				#region server notice event handler
				client.ServerNotice += delegate(object sender, ServerEventArgs e)
				{
					Irc.Objects.Message m = new Irc.Objects.Message();
					m.Text = e.Message.Sender + ": " + e.Message.Text;
					ServerWindow.AddMessage(m);
				};
				client.ErrorMessage += delegate(object sender, ServerEventArgs e)
				{
					Irc.Objects.Message m = new Irc.Objects.Message();
					m.Text = "["+e.Message.Sender+"] Error: "+ e.Message.Text;
					ServerWindow.AddMessage(m);
				};
				client.Connecting += delegate(object sender, ConnectEventArgs e)
				{
					Irc.Objects.Message m = new Irc.Objects.Message();
					m.Text = "Connecting to " + e.Server;
					ServerWindow.AddMessage(m);
				};
				#endregion
				#region motd event handler
				client.MotdReady += delegate(object sender, MotdEventArgs e)
				{
					Irc.Objects.Message m = new Irc.Objects.Message();
					m.Text = "MOTD for "+e.Motd.Target+":\n"+e.Motd.Message;
					ServerWindow.AddMessage(m);
				};
				#endregion
				#region ctcp event handler
				client.CtcpMessage += delegate(object sender, CtcpEventArgs e)
				{
					if(e.Message.Text == "version")
					{
						string version = Application.ProductVersion, version2 = System.Reflection.Assembly.GetAssembly(typeof(Client)).GetName().Version.ToString();
						Ctcp reply = new Ctcp();
						reply.Target = e.Message.Sender;
						reply.Text = "version";
						reply.Parameters = "IRC.NET Version " + version + ", Client library version " + version2;
						client.CtcpReply(reply);
					}
				};
				#endregion
				#region join event handler
				client.SelfJoin += delegate(object sender, JoinEventArgs e)
				{
					if(e.Movement is UserJoin)
					{
						TabPage tab = new TabPage(((Channel)e.Movement.Target).Name);
						tab.Name = ((Channel)e.Movement.Target).Name;
						ChannelTab channel = new ChannelTab((Channel)e.Movement.Target);
						tab.Controls.Add(channel);
						ContextMenuStrip menu = new ContextMenuStrip();
						menu.ShowImageMargin = false;
						menu.Items.Add(new ToolStripMenuItem("Close", null, new EventHandler(CloseChannel), ((Channel)e.Movement.Target).Name));
						tab.ContextMenuStrip = menu;
						tab.MouseClick += delegate(object s, MouseEventArgs ev) {
							if(ev.Button == MouseButtons.Right)
								tab.ContextMenuStrip.Show();
						};
						tabs.BeginInvoke((MethodInvoker)delegate {
							tabs.Controls.Add(tab);
							if(SettingsManager.Instance.AutofocusChannels == true)
								tabs.SelectTab(tab);
						});
					} else if(e.Movement is UserPart)
						tabs.BeginInvoke((MethodInvoker)delegate { tabs.Controls.Remove(tabs.Controls.Find(((Channel)e.Movement.Target).Name, false)[0]); });
				};
				#endregion
				#region message event handlers
				client.PrivateMessage += delegate(object sender, MessageEventArgs e)
				{
					AddPrivateMessage((Nickname)(((Nickname)((PrivateMessage)e.Message).Target) == client.Nickname ? ((PrivateMessage)e.Message).Sender : e.Message.Target), String.Format(Strings.MessageText, e.Message.Sender, e.Message.Text));
				};
				client.PrivateNotice += delegate(object sender, MessageEventArgs e)
				{
					AddPrivateMessage((Nickname)(((Nickname)((PrivateMessage)e.Message).Target) == client.Nickname ? ((PrivateMessage)e.Message).Sender : e.Message.Target), String.Format(Strings.NoticeText, e.Message.Sender, e.Message.Text));
				};
				client.PrivateAction += delegate(object sender, MessageEventArgs e)
				{
					AddPrivateMessage((Nickname)(((Nickname)((PrivateMessage)e.Message).Target) == client.Nickname ? ((PrivateMessage)e.Message).Sender : e.Message.Target), String.Format(Strings.ActionText, e.Message.Sender, e.Message.Text));
				};
				#endregion
				Show();
			}
			else
			{
				MessageBox.Show("Invalid connection string!\r\nThe connection string must be in the format:\r\nirc(s)://(server):(port)", "Error!",	MessageBoxButtons.OK, MessageBoxIcon.Error);
				Close();
			}
		}

		public ChannelTab[] ChannelWindows
		{
			get {
				List<ChannelTab> channels = new List<ChannelTab>();
				foreach(TabPage channel in tabs.TabPages)
				{
					if(channel.Controls[0] is ChannelTab)
						channels.Add((ChannelTab)channel.Controls[0]);
				}
				return channels.ToArray();
			}
		}
		public MessageTab[] MessageWindows
		{
			get {
				List<MessageTab> messages = new List<MessageTab>();
				foreach(TabPage message in tabs.TabPages)
				{
					if(message.Controls[0] is MessageTab)
						messages.Add((MessageTab)message.Controls[0]);
				}
				return messages.ToArray();
			}
		}
		public ServerTab ServerWindow
		{
			get {
				if(serverTab.Controls.Count > 0)
					return (ServerTab)serverTab.Controls[0];
				else
					return null;
			}
		}

		public TabPage FindTabByControl(Control control)
		{
			return tabs.GetTabPageByControl(control);
		}
		private bool ValidateCert(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors)
		{
			if(sslPolicyErrors != SslPolicyErrors.None)
				return MessageBox.Show("The server you are connecting to has problems with its SSL Certificate!" +
				                " Are you sure you trust " + certificate.Issuer + " as a certificate issuer for " +
				                certificate.Subject + "?",
				                "Alert!", MessageBoxButtons.YesNo, MessageBoxIcon.Error, MessageBoxDefaultButton.Button2) == DialogResult.Yes;
			return sslPolicyErrors == SslPolicyErrors.None;
		}
		private void AddPrivateMessage(Nickname sender, string message)
		{
			tabs.BeginInvoke((MethodInvoker)delegate {
				MessageTab target = null;
				Control[] windows = tabs.Controls.Find(sender, false);
				if(windows.Length == 1)
				{
					target = windows[0].Controls[0] as MessageTab;
				}
				else
				{
					TabPage tab = new TabPage(sender);
					tab.Name = sender;
					MessageTab messageWindow = new MessageTab(sender);
					tab.Controls.Add(messageWindow);
					tabs.Controls.Add(tab);
					if(SettingsManager.Instance.AutofocusMessages == true)
						tabs.SelectedTab = tab;
					target = messageWindow;
				}
				PrivateMessage pm = new PrivateMessage();
				pm.Sender = sender;
				pm.Target = client.Nickname;
				pm.Text = message;
				target.AddMessage(pm);
			});
		}
		private void CloseNetwork(object sender, FormClosedEventArgs e)
		{
			if(IsConnected)
				client.Disconnect();
		}
		public void Connect()
		{
			if(!client.Registered)
			{
				client.Connect();
			}
		}
		public void Disconnect()
		{
			if(client.Registered)
			{
				client.Disconnect();
			}
		}
		private void CloseChannel(object sender, EventArgs e)
		{
			((ChannelTab)((TabPage)((ContextMenuStrip)((ToolStripItem)sender).Owner).SourceControl).Controls[0]).PartChannel();
		}
	}
}
